﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LibGit2Sharp;
using MetroFramework;
using MetroFramework.Controls;
using MetroFramework.Forms;
using Newtonsoft.Json;

namespace BakaGit
{
    public partial class Form1 : BaseForm
    {
        public Form1()
        {
            InitializeComponent();
            
        }
        List<GitProject> projects = new List<GitProject>();
        private void Form1_Load(object sender, EventArgs e)
        {
            this.Text = Program.info.repoName + " - " + "BakaGit";
            loadRepoStatus();
        }

        #region CodeCommit
        public void loadRepoStatus() {
            LibGit2Sharp.RepositoryStatus status = Program.repository.RetrieveStatus(new LibGit2Sharp.StatusOptions());
            if (status.IsDirty)
            {
                btnDoCommit.Enabled = true;
                btnGenerateCommitMsg.Enabled = true;
                lblRepoStatus.Text = "项目状态："+status.Count(f => f.State != LibGit2Sharp.FileStatus.Unaltered && f.State != FileStatus.Ignored)+"个已修改文件";
            }
            else
            {
                btnDoCommit.Enabled = false;
                btnGenerateCommitMsg.Enabled = false;
                lblRepoStatus.Text = "项目状态： 所有代码都已提交";
            }

            btnReloadCommits_Click(null, null);
        }
        private void btnRefreshCommit_Click(object sender, EventArgs e)
        {
            loadRepoStatus();
        }
        private void btnOpenFolder_Click(object sender, EventArgs e)
        {
            Process.Start(new ProcessStartInfo("explorer", "\""+Path.Combine(Environment.CurrentDirectory, Program.info.localPath)+"\""));
        }


        private void btnGenerateCommitMsg_Click(object sender, EventArgs e)
        {
            if(txtCommitMsg.Text=="" || MetroMessageBox.Show(this,"是否覆盖已有内容","",MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                LibGit2Sharp.RepositoryStatus status = Program.repository.RetrieveStatus(new LibGit2Sharp.StatusOptions());
                StringBuilder sb = new StringBuilder();

                status.Untracked.ToList().ForEach(f => sb.Append("Add ").Append(f.FilePath).AppendLine());
                status.Modified.ToList().ForEach(f => sb.Append("Update ").Append(f.FilePath).AppendLine());

                status.Added.ToList().ForEach(f => sb.Append("Add  ").Append(f.FilePath).AppendLine());
                status.RenamedInWorkDir.ToList().ForEach(f => sb.Append("Move ").Append(f.FilePath).AppendLine());
                status.RenamedInIndex.ToList().ForEach(f => sb.Append("Move ").Append(f.FilePath).AppendLine());

                status.Missing.ToList().ForEach(f => sb.Append("Delete ").Append(f.FilePath).AppendLine());
                status.Removed.ToList().ForEach(f => sb.Append("Delete ").Append(f.FilePath).AppendLine());
                sb.Append("# Auto Generated by BakaGit");
                txtCommitMsg.Text = sb.ToString();
            }
            fixWindowTop();
        }

        void RunOnUIThread(Action a)
        {
            BeginInvoke(a);
            Application.DoEvents();
            //Invoke(new Action(() =>
            //{
            //    a();
            //    Application.DoEvents();
            //}));
        }

        private void btnDoCommit_Click(object sender, EventArgs e)
        {

            if (txtCommitMsg.Text.Trim() == "" )
            {
                MetroMessageBox.Show(this, "请填写提交描述", "");
                fixWindowTop();
                return;
            }

            btnDoCommit.Text = "提交中";
            btnDoCommit.Enabled = false;
            //git add .
            Repository repo = Program.repository;
            Commands.Stage(repo, "*");

            //git commit -m ""
            repo.Commit(txtCommitMsg.Text, Program.me, Program.me);
            //git push
            PushOptions pushOptions = new PushOptions()
            {
                CertificateCheck = (cert, valid, host) => true,
                CredentialsProvider = (url, username, supportCredentials) => Program.credential,
                OnPackBuilderProgress = (stage,current,total) => { 
                    
                    RunOnUIThread(() =>
                    {
                        btnDoCommit.Text = (stage.ToString() + " (" + current + "/" + total + ")");
                    });
                    return true;
                },
                OnPushTransferProgress = (current,total,bytes) => {
                    RunOnUIThread(() =>
                    {
                        btnDoCommit.Text = ("上传 " + " (" + current + "/" + total + ")");
                    });
                    if(current == total)
                    {
                        RunOnUIThread(() =>
                        {
                            btnDoCommit.Text = "提交代码";
                            btnDoCommit.Enabled = true;
                            txtCommitMsg.Text = "";
                            MetroMessageBox.Show(this, "提交成功", " ");
                            fixWindowTop();
                            loadRepoStatus();
                        });
                        
                    }
                    return true; 
                },
                OnPushStatusError = (err) => {
                    RunOnUIThread(() =>
                    {
                        MetroMessageBox.Show(this, "提交出错：\r\n" + err.Message, "错误");
                        fixWindowTop();
                        btnDoCommit.Text = "提交代码";
                        btnDoCommit.Enabled = true;
                        undoRepoCommit();
                        loadRepoStatus();
                    });
                    
                },
                
            };
            try
            {
                repo.Network.Push(repo.Head, pushOptions);
            }catch(Exception ex)
            {
                MetroMessageBox.Show(this, "提交出错："+ex.GetType().Name+"\r\n" + ex.Message, "错误");
                fixWindowTop();
                btnDoCommit.Text = "提交代码";
                btnDoCommit.Enabled = true;
                undoRepoCommit();
                loadRepoStatus();
            }
        }

        void undoRepoCommit() {
            Repository repo = Program.repository;
            Commit commit = repo.Head.Commits.Count() > 1 ? repo.Head.Commits.ElementAt(1) : null;
            if (commit != null)
            {
                repo.Reset(ResetMode.Mixed, commit);
            }
        }

        #endregion

        #region Pull
        private void btnPull_Click(object sender, EventArgs e)
        {
            btnPull.Enabled = false;
            btnPull.Text = "正在获取更新...";
            Repository repo = Program.repository;
            PullOptions options = new PullOptions();
            options.FetchOptions = new FetchOptions();
            options.MergeOptions = new MergeOptions();
            options.FetchOptions.CertificateCheck = (cert, valid, host) => true;
            options.FetchOptions.CredentialsProvider = (url, username, accept) => Program.credential;
            
            options.MergeOptions.FailOnConflict = true;
            try
            {
                MergeResult result = Commands.Pull(repo, Program.me, options);
                if(result.Status != MergeStatus.Conflicts)
                {
                    btnPull.Enabled = true;
                    btnPull.Text = "检查更新";
                    int beforeCount = tblCommits.Rows.Count;
                    loadRepoStatus();
                    int afterCount = tblCommits.Rows.Count;
                    if (result.Status == MergeStatus.UpToDate)
                    {
                        MetroMessageBox.Show(this, "当然代码已经是最新", "检查更新");
                        fixWindowTop();
                    }
                    else {
                        MetroMessageBox.Show(this, "更新完成，下载了"+(afterCount - beforeCount)+"个提交", "检查更新");
                        fixWindowTop();
                    }
                }
            }
            catch (Exception ex)
            {
                MetroMessageBox.Show(this, "检查更新出错：" + ex.GetType().Name + "\r\n" + ex.Message, "错误");
                fixWindowTop();
                btnPull.Enabled = true;
                btnPull.Text = "检查更新";
            }
        }




        #endregion

        private void btnReloadCommits_Click(object sender, EventArgs e)
        {
            tblCommits.Rows.Clear();
            Program.repository.Head.Commits.ToList().ForEach(c =>
            {
                tblCommits.Rows.Add(
                    c.Author.When.ToString("yy\\-MM\\-dd HH\\:mm\\:ss"),
                    c.Author.Name,
                    c.Message
                    );
                if(tblCommits.RowCount % 2 == 0)
                {
                    tblCommits.Rows[tblCommits.RowCount - 1].DefaultCellStyle.BackColor = Color.LightGray;
                    tblCommits.Rows[tblCommits.RowCount - 1].DefaultCellStyle.SelectionBackColor = Color.LightGray;
                }
            });
        }

        private void metroButton3_Click(object sender, EventArgs e)
        {
            if (!System.Text.RegularExpressions.Regex.IsMatch(txtEmail.Text, "^.*@.*$"))
            {
                txtEmail.WithError = true;
                MetroFramework.MetroMessageBox.Show(this, "请输入正确的电子邮箱", " ");
                fixWindowTop();
                return;
            }
            if (txtUn.Text.Length < 1)
            {
                txtUn.WithError = true;
                MetroFramework.MetroMessageBox.Show(this, "请输入用户名", " ");
                fixWindowTop();
                return;
            }

            if (txtPw.Text.Length < 6)
            {
                txtPw.WithError = true;
                MetroFramework.MetroMessageBox.Show(this, "请输入密码", " ");
                fixWindowTop();
                return;
            }

            Program.info.username = txtUn.Text;
            Program.info.SetPasswordEncrypted(txtPw.Text);
            Program.info.email = txtEmail.Text;
            File.WriteAllText(Program.configpath, JsonConvert.SerializeObject(Program.info));
            MetroFramework.MetroMessageBox.Show(this, "保存成功", " ");
            fixWindowTop();
        }

        private void btnUpdatePw_Click(object sender, EventArgs e)
        {
            showPanel(tblModifyPassword);
            txtUn.Text = Program.info.username;
            txtPw.Text = Program.info.GetPasswordDecrypted();
            txtEmail.Text = Program.info.email;
        }
        private void btnSwitchBranch_Click(object sender, EventArgs e)
        {
            showPanel(tblSwitchBranch);
            IEnumerable<Branch> branches = Program.repository.Branches.Where(b => b.IsRemote == false && b.IsTracking == true);
            Branch head = branches.FirstOrDefault(b => b.IsCurrentRepositoryHead);
            cmbBranch.setDict(branches.ToDictionary(b => b.FriendlyName));
            cmbBranch.SelectedValue =head;
            btnDoSwitchBranch.Enabled = cmbBranch.Enabled;

        }

        private void btnDoSwitchBranch_Click(object sender, EventArgs e)
        {
            if (MetroMessageBox.Show(this, "切换分支将会覆盖现有未提交的代码，请确保所有代码已提交。", "", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                try
                {
                    Commands.Checkout(Program.repository, (Branch)cmbBranch.SelectedValue);
                    MetroFramework.MetroMessageBox.Show(this, "切换成功", " ");
                    fixWindowTop();
                    loadRepoStatus();
                }
                catch(Exception ex)
                {
                    MetroMessageBox.Show(this, "切换出错：\r\n" + ex.Message, "错误");
                    fixWindowTop();
                }
            }
            fixWindowTop();
        }
        void showPanel(MetroPanel panel)
        {
            tblModifyPassword.Visible = false;
            tblSwitchBranch.Visible = false;
            panel.Visible = true;
            panel.Location = ptrPanel.Location;
        }

       
    }
}
